-
Notifications
You must be signed in to change notification settings - Fork 32
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: support voice agent api #360
Conversation
Warning Rate limit exceeded@naomi-lgbt has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 9 minutes and 8 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (2)
WalkthroughThis pull request introduces several new projects to the Deepgram .NET SDK, enhancing WebSocket-based agent communication. It adds four projects to the solution, implements a new WebSocket client class for agent interactions, and includes methods for creating agent WebSocket clients. Additionally, multiple model classes for agent-related responses and configurations are introduced, along with a sample agent application that demonstrates the new functionalities. Changes
Sequence DiagramsequenceDiagram
participant Client as WebSocket Client
participant Deepgram as Deepgram API
Client->>Deepgram: Connect with Configuration
Deepgram-->>Client: Welcome Response
Client->>Deepgram: Start Audio Streaming
Deepgram-->>Client: Audio Responses
Client->>Deepgram: Send Text/Function Calls
Deepgram-->>Client: Conversation Text/Function Responses
Client->>Deepgram: Close Connection
Possibly related PRs
Suggested reviewers
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 22
🧹 Nitpick comments (73)
Deepgram/Models/Agent/v2/WebSocket/UserStartedSpeakingResponse.cs (1)
17-23
: Optimize ToString implementation and add missing using directives.The current implementation has several potential issues:
- Missing using directives for
System.Text.Json
andSystem.Text.RegularExpressions
- No null check before serialization
- Unnecessary use of
Regex.Unescape
on every call- Could benefit from caching since the object is immutable
Add these using directives at the top of the file:
+using System.Text.Json; +using System.Text.RegularExpressions;Consider optimizing the implementation:
+ private string? _cachedString; + /// <summary> /// Override ToString method to serialize the object /// </summary> public override string ToString() { - return Regex.Unescape(JsonSerializer.Serialize(this, JsonSerializeOptions.DefaultOptions)); + return _cachedString ??= JsonSerializer.Serialize(this, JsonSerializeOptions.DefaultOptions); }Note: Removed
Regex.Unescape
as it's typically not needed for JSON serialization unless you're dealing with special characters that need unescaping.Deepgram/Models/Agent/v2/WebSocket/AgentType.cs (1)
9-28
: Add XML documentation and consider enum value organization.The enum implementation could be improved in several ways:
- Add XML documentation for the enum and its values to support IntelliSense.
- Explicitly set values for agent-specific states to prevent issues if
WebSocketType
values change.- Consider grouping related states using regions or comments.
Here's a suggested implementation:
+/// <summary> +/// Represents the various states and message types in the agent WebSocket communication. +/// </summary> public enum AgentType { // Base WebSocket states Open = WebSocketType.Open, Close = WebSocketType.Close, Unhandled = WebSocketType.Unhandled, Error = WebSocketType.Error, // Agent conversation states - Welcome, - ConversationText, - UserStartedSpeaking, - AgentThinking, + Welcome = 100, + ConversationText = 101, + UserStartedSpeaking = 102, + AgentThinking = 103, // Function calling states - FunctionCallRequest, - FunctionCalling, + FunctionCallRequest = 200, + FunctionCalling = 201, // Audio states - AgentStartedSpeaking, - AgentAudioDone, - Audio, + AgentStartedSpeaking = 300, + AgentAudioDone = 301, + Audio = 302, // Configuration states - InjectionRefused, - SettingsApplied, - InstructionsUpdated, - SpeakUpdated, + InjectionRefused = 400, + SettingsApplied = 401, + InstructionsUpdated = 402, + SpeakUpdated = 403, }Deepgram/Models/Agent/v2/WebSocket/Audio.cs (1)
7-16
: Consider making properties immutable for thread safety.The record type suggests immutability, but the properties have public setters. For thread safety and to better align with record semantics, consider making the properties init-only.
- public Input Input { get; set; } = new Input(); + public Input Input { get; init; } = new Input(); - public Output Output { get; set; } = new Output(); + public Output Output { get; init; } = new Output();Deepgram/Models/Agent/v2/WebSocket/Output.cs (2)
9-15
: Document the significance of default values.The default values (
"linear16"
for Encoding and24000
for SampleRate) seem to be magic numbers. Consider:
- Adding XML documentation to explain their significance
- Using constants to improve maintainability
+ /// <summary> + /// Default audio encoding format compatible with Deepgram's voice agent API. + /// </summary> + private const string DefaultEncoding = "linear16"; + + /// <summary> + /// Default sample rate (in Hz) for optimal voice processing. + /// </summary> + private const long DefaultSampleRate = 24000; - public string Encoding { get; set; } = "linear16"; + public string Encoding { get; set; } = DefaultEncoding; - public long? SampleRate { get; set; } = 24000; + public long? SampleRate { get; set; } = DefaultSampleRate;
17-23
: Add validation for Bitrate property.Consider adding validation to ensure the Bitrate value is positive when set.
+ private long? _bitrate; [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("bitrate")] - public long? Bitrate { get; set; } + public long? Bitrate + { + get => _bitrate; + set + { + if (value.HasValue && value.Value <= 0) + throw new ArgumentOutOfRangeException(nameof(value), "Bitrate must be positive"); + _bitrate = value; + } + }Deepgram/Clients/Agent/v2/Websocket/Client.cs (8)
18-25
: Add XML summary for the constructor.
The constructor lacks an XML doc comment explaining its purpose, parameters, and usage. Providing it helps maintain consistent documentation and improves clarity for consumers of this class./// <param name="apiKey">Required DeepgramApiKey</param> /// <param name="deepgramClientOptions"><see cref="IDeepgramClientOptions"/> for HttpClient Configuration</param> +/// <summary> +/// Initializes a new instance of the <see cref="Client"/> class, setting up +/// the Deepgram API key and client options for Agent WebSocket communication. +/// </summary> public Client(string? apiKey = null, IDeepgramClientOptions? options = null) : base(apiKey, options) { Log.Verbose("AgentWSClient", "ENTER");
27-44
: Align event naming or add individual summaries.
The private events from_audioReceived
to_speakUpdatedReceived
share a single documentation snippet indicating “Fires when an event is received,” but each event actually targets a different response type. To make the code more self-explanatory, add or adjust comments to clarify when each event is fired and its intended usage.
105-129
: Consolidate wrapped event subscriptions for typed “Open” / “Close” / “Error” / “Unhandled” events.
Each of these methods follows a similar pattern: create a wrapped handler, cast arguments, and subscribe via the base method. Consider creating a helper method to reduce duplication and improve readability.-private async Task<bool> SubscribeForCommonEvent<TCommon, TSpecific>( - EventHandler<TSpecific> userHandler, - Func<Common.TCommon, TSpecific> castFunc) -{ - // code to wrap and subscribe -}Also applies to: 389-410
135-387
: Consider adding unsubscribe support & a unified pattern for these subscription methods.
All subscription methods add their handlers to private events but never provide an unsubscribe mechanism. If a consumer repeatedly subscribes to the same event type, memory leaks or unexpected behavior may occur. Additionally, these subscription methods share repeated code blocks. Refactoring them into a common “subscribe event” helper (or using a dictionary-based approach) would reduce duplication and potential confusion.
483-523
: Key concurrency detail in keep-alive loop.
The loop sleeps for a hard-coded 5 seconds and continues indefinitely until disconnected or canceled. Consider making the interval configurable. Also ensure that_cancellationTokenSource
is disposed once completed.
554-555
: Typo in log message “Excepton”.
Minor spelling error in the log message could cause confusion during troubleshooting or searching logs.-Log.Verbose("ProcessDataReceived", $"Excepton: {ex}"); +Log.Verbose("ProcessDataReceived", $"Exception: {ex}");
560-809
: Handle invalid or missing “type” gracefully in the switch statement.
Whendata.RootElement.GetProperty("type")
is missing or invalid,Enum.Parse
will fail with an exception. To improve robustness, consider usingEnum.TryParse
and handle unrecognized event types more gracefully.-var val = Enum.Parse(typeof(AgentType), data.RootElement.GetProperty("type").GetString()!); +if (!Enum.TryParse<AgentType>(data.RootElement.GetProperty("type").GetString(), out var val)) +{ + Log.Warning("ProcessTextMessage", "Received unknown or invalid AgentType."); + base.ProcessTextMessage(result, ms); + return; +}
835-858
: Prevent potential double slash in URI construction.
When appending theUriSegments.AGENT
constant tobaseAddress
, ensure no extra slash is added ifbaseAddress
already ends with one. This avoids issues with misconfigured endpoints or future changes toUriSegments.AGENT
.-if (baseAddress.EndsWith("/")) - return new Uri($"{baseAddress}{UriSegments.AGENT}"); -else - return new Uri($"{baseAddress}/{UriSegments.AGENT}"); +if (!baseAddress.EndsWith("/")) +{ + baseAddress += "/"; +} +return new Uri($"{baseAddress}{UriSegments.AGENT}");Deepgram/Clients/Agent/v2/Websocket/ResponseEvent.cs (1)
7-10
: Clarify usage of primary constructor vs. record syntax.
C# primary constructors are typically used in records. Given this class inheritsEventArgs
, consider using a standard class or record instead. If immutability is desired, a record with read-only properties might be preferable. Additionally, a brief summary comment clarifying usage would help.-public class ResponseEvent<T>(T? response) : EventArgs +/// <summary> +/// Encapsulates an event response of type T. +/// </summary> +public class ResponseEvent<T> : EventArgs +{ + public ResponseEvent(T? response) + { + Response = response; + } + public T? Response { get; set; } }Deepgram/AgentWebSocketClient.cs (1)
13-18
: Add summary doc & rename constructor parameters to match base usage.
The constructor lacks an XML doc comment. Also, for clarity, consider naming the parameteroptions
instead ofdeepgramClientOptions
, mirroring the base constructor’s signature. This can reduce confusion for SDK users./// <summary> /// Implements the latest supported version of the Agent Client. /// </summary> public class AgentWebSocketClient : Client { - public AgentWebSocketClient(string apiKey = "", DeepgramWsClientOptions? deepgramClientOptions = null) - : base(apiKey, deepgramClientOptions) + /// <summary> + /// Initializes a new instance of the <see cref="AgentWebSocketClient"/> class for contemporary Deepgram agent usage. + /// </summary> + public AgentWebSocketClient(string apiKey = "", DeepgramWsClientOptions? options = null) + : base(apiKey, options) { } }Deepgram/Clients/Agent/v2/Websocket/UriSegments.cs (2)
9-11
: Consider making the agent URI configurable.While hardcoding "agent.deepgram.com" works for production, it might limit testing against different environments. Consider making this configurable through environment variables or configuration settings.
7-16
: Add XML documentation for better IntelliSense support.Consider adding XML documentation to describe the purpose and usage of these constants.
public static class UriSegments { + /// <summary> + /// The base URI for Deepgram's agent API endpoint. + /// </summary> public const string AGENT_URI = "agent.deepgram.com"; + /// <summary> + /// The agent endpoint segment used in API routes. + /// </summary> public const string AGENT = "agent"; }Deepgram/Models/Agent/v2/WebSocket/Provider.cs (2)
9-11
: Add XML documentation for the Type property.Add XML documentation to describe the expected values and purpose of the Type property.
+ /// <summary> + /// Gets or sets the provider type. + /// </summary> [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("type")] public string Type { get; set; }
7-12
: Consider using an enum for the Type property.Using a string for Type could lead to runtime errors if invalid values are provided. Consider using an enum to enforce valid provider types at compile-time.
+public enum ProviderType +{ + [JsonPropertyName("type1")] + Type1, + [JsonPropertyName("type2")] + Type2, + // Add other valid types +} public record Provider { [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("type")] - public string Type { get; set; } + public ProviderType Type { get; set; }Deepgram/Models/Agent/v2/WebSocket/Properties.cs (2)
13-13
: Remove extra blank line.Remove the unnecessary blank line to maintain consistent formatting.
9-11
: Add XML documentation for the Item property.Add XML documentation to describe the purpose and nullable nature of the Item property.
+ /// <summary> + /// Gets or sets the item associated with these properties. + /// </summary> [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("item")] public Item? Item { get; set; }Deepgram/Models/Agent/v2/WebSocket/Listen.cs (2)
11-11
: Consider making the model version configurable.The default model version "nova-2" is hardcoded. Consider making this configurable to support future model versions without code changes.
9-11
: Add XML documentation and validation for the Model property.Add XML documentation and consider adding validation to ensure the model version is supported.
+ /// <summary> + /// Gets or sets the model version to use for speech recognition. + /// Default value is "nova-2". + /// </summary> [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("model")] - public string Model { get; set; } = "nova-2"; + public string Model + { + get => _model; + set + { + if (string.IsNullOrEmpty(value)) + throw new ArgumentException("Model version cannot be null or empty"); + _model = value; + } + } + + private string _model = "nova-2";Deepgram/Models/Agent/v2/WebSocket/Speak.cs (2)
7-12
: Add XML documentation and consider making the model name configurable.The
Model
property lacks XML documentation. Additionally, the hardcoded model name "aura-asteria-en" should ideally be configurable or defined as a constant.public record Speak { + /// <summary> + /// The voice model to use for speech synthesis. + /// </summary> + /// <remarks> + /// Available models: + /// - aura-asteria-en: Default English voice model + /// </remarks> [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("model")] - public string Model { get; set; } = "aura-asteria-en"; + public string Model { get; set; } = SpeakModels.Default; } + public static class SpeakModels + { + public const string Default = "aura-asteria-en"; + }
16-19
: Add return value documentation for ToString.The XML documentation for the
ToString
override should include information about the return value./// <summary> /// Override ToString method to serialize the object /// </summary> + /// <returns>A JSON string representation of the object.</returns>
Deepgram/Models/Agent/v2/WebSocket/KeepAliveSchema.cs (1)
7-15
: Consider using a record and fix documentation.
- The XML documentation incorrectly mentions "SettingsConfiguration".
- Since
Type
is effectively readonly, consider:
- Making this a record
- Using init-only property
- public class KeepAliveSchema + public record KeepAliveSchema { /// <summary> - /// SettingsConfiguration event type. + /// The keep-alive message type. /// </summary> [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("type")] - public string? Type { get; } = AgentClientTypes.KeepAlive; + public string? Type { get; init; } = AgentClientTypes.KeepAlive;Deepgram/Models/Agent/v2/WebSocket/Header.cs (1)
17-23
: Add return value documentation for ToString.The XML documentation for the
ToString
override should include information about the return value./// <summary> /// Override ToString method to serialize the object /// </summary> + /// <returns>A JSON string representation of the object.</returns>
Deepgram/Models/Agent/v2/WebSocket/Item.cs (1)
9-15
: Add XML documentation for properties.Properties lack XML documentation. Add summary tags to describe their purpose and usage.
public record Item { [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("type")] + /// <summary> + /// Gets or sets the type of the item. + /// </summary> public string? Type { get; set; } [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("description")] + /// <summary> + /// Gets or sets the description of the item. + /// </summary> public string? Description { get; set; }Deepgram/Models/Agent/v2/WebSocket/Context.cs (1)
13-15
: Add XML documentation for properties.Properties lack XML documentation. Add summary tags to describe their purpose and usage.
+ /// <summary> + /// Gets or sets the list of messages in the content. + /// </summary> public List<object>? Messages { get; set; } + /// <summary> + /// Gets or sets a value indicating whether replay is enabled. + /// </summary> public bool? Replay { get; set; }Deepgram/Models/Agent/v2/WebSocket/SettingsAppliedResponse.cs (3)
1-1
: Update copyright year to 2024.The copyright year should be 2024 as we're currently in January 2025.
-// Copyright 2025 Deepgram .NET SDK contributors. All Rights Reserved. +// Copyright 2024 Deepgram .NET SDK contributors. All Rights Reserved.
9-11
: Fix incorrect XML documentation.The XML documentation refers to "SettingsConfiguration" instead of "SettingsApplied".
/// <summary> - /// SettingsConfiguration event type. + /// SettingsApplied event type. /// </summary>
17-20
: Enhance XML documentation for ToString method.Add return value documentation using
<returns>
tag./// <summary> /// Override ToString method to serialize the object /// </summary> + /// <returns>A JSON string representation of the object.</returns>
Deepgram/Models/Agent/v2/WebSocket/Input.cs (3)
9-11
: Add XML documentation for Encoding property.Document the property's purpose and default value.
+ /// <summary> + /// Gets or sets the audio encoding format. + /// Default value is "linear16". + /// </summary> [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("encoding")] public string Encoding { get; set; } = "linear16";
13-15
: Add XML documentation for SampleRate property.Document the property's purpose and default value.
+ /// <summary> + /// Gets or sets the audio sample rate in Hz. + /// Default value is 24000. + /// </summary> [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("sample_rate")] public long? SampleRate { get; set; } = 24000;
7-16
: Add input validation for Encoding and SampleRate properties.Consider adding validation to ensure valid values are set:
- Encoding should be validated against supported formats
- SampleRate should be within acceptable range
public record Input { + private string _encoding = "linear16"; + private long? _sampleRate = 24000; + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("encoding")] - public string Encoding { get; set; } = "linear16"; + public string Encoding + { + get => _encoding; + set + { + if (!IsValidEncoding(value)) + throw new ArgumentException("Invalid encoding format", nameof(value)); + _encoding = value; + } + } [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("sample_rate")] - public long? SampleRate { get; set; } = 24000; + public long? SampleRate + { + get => _sampleRate; + set + { + if (value.HasValue && (value < 8000 || value > 48000)) + throw new ArgumentException("Sample rate must be between 8000 and 48000 Hz", nameof(value)); + _sampleRate = value; + } + } + + private static bool IsValidEncoding(string encoding) => + encoding?.ToLowerInvariant() switch + { + "linear16" or "mulaw" or "alaw" => true, + _ => false + };Deepgram/Models/Agent/v2/WebSocket/InjectionRefusedResponse.cs (2)
1-1
: Update copyright year to 2024.The copyright year should be 2024 as we're currently in January 2025.
-// Copyright 2025 Deepgram .NET SDK contributors. All Rights Reserved. +// Copyright 2024 Deepgram .NET SDK contributors. All Rights Reserved.
9-11
: Fix incorrect XML documentation.The XML documentation refers to "SettingsConfiguration" instead of "InjectionRefused".
/// <summary> - /// SettingsConfiguration event type. + /// InjectionRefused event type. /// </summary>Deepgram/Models/Agent/v2/WebSocket/FunctionCallRequestResponse.cs (2)
9-11
: Fix incorrect XML documentation.The XML documentation refers to "SettingsConfiguration" instead of "FunctionCallRequest".
/// <summary> - /// SettingsConfiguration event type. + /// FunctionCallRequest event type. /// </summary>
1-26
: Ensure consistency across WebSocket response models.Consider the following architectural improvements:
- Standardize property mutability:
Input.cs
uses mutable properties- Other models use init-only properties
- Create a base response class/interface:
- All models have
Type
andToString()
implementation- Common serialization logic could be shared
- Add XML documentation templates:
- Standardize documentation format
- Include examples in documentation
Example base class:
public abstract record AgentResponseBase { [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("type")] [JsonConverter(typeof(JsonStringEnumConverter))] public AgentType? Type { get; init; } public override string ToString() => Regex.Unescape(JsonSerializer.Serialize(this, JsonSerializeOptions.DefaultOptions)); }Deepgram/Models/Agent/v2/WebSocket/UpdateSpeakSchema.cs (3)
9-14
: Fix incorrect XML documentation for Type propertyThe XML comment incorrectly states "SettingsConfiguration event type" when it should describe the UpdateSpeak event type.
/// <summary> - /// SettingsConfiguration event type. + /// UpdateSpeak event type. /// </summary>
16-18
: Add XML documentation for Model propertyMissing XML documentation for the Model property. Add a summary describing its purpose and any constraints.
+ /// <summary> + /// The model to be used for speech synthesis. + /// </summary> [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("model")]
23-26
: Add error handling to ToString methodThe ToString method should handle potential serialization errors to prevent runtime exceptions.
public override string ToString() { - return Regex.Unescape(JsonSerializer.Serialize(this, JsonSerializeOptions.DefaultOptions)); + try + { + return Regex.Unescape(JsonSerializer.Serialize(this, JsonSerializeOptions.DefaultOptions)); + } + catch (JsonException ex) + { + return $"{{\"error\": \"Failed to serialize {nameof(UpdateSpeakSchema)}: {ex.Message}\"}}"; + } }Deepgram/Models/Agent/v2/WebSocket/InjectAgentMessageSchema.cs (1)
16-18
: Add XML documentation for Message propertyMissing XML documentation for the Message property.
+ /// <summary> + /// The message to be injected into the agent's processing workflow. + /// </summary> [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("message")]Deepgram/Models/Agent/v2/WebSocket/UpdateInstructionsSchema.cs (1)
16-18
: Add XML documentation for Instructions propertyMissing XML documentation for the Instructions property.
+ /// <summary> + /// The updated instructions for the agent's behavior. + /// </summary> [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("instructions")]Deepgram/Models/Agent/v2/WebSocket/WelcomeResponse.cs (2)
17-19
: Add XML documentation for SessionId propertyMissing XML documentation for the SessionId property.
+ /// <summary> + /// The unique identifier for the WebSocket session. + /// </summary> [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("session_id")]
1-28
: Consider introducing a base class for common functionalityAll schema/response classes share common patterns for JSON serialization and ToString implementation. Consider extracting these into a base class or interface to promote DRY principles and ensure consistent error handling.
Example base class:
public abstract class WebSocketMessageBase { [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("type")] public abstract string? Type { get; } public override string ToString() { try { return Regex.Unescape(JsonSerializer.Serialize(this, JsonSerializeOptions.DefaultOptions)); } catch (JsonException ex) { return $"{{\"error\": \"Failed to serialize {GetType().Name}: {ex.Message}\"}}"; } } }Deepgram/Models/Agent/v2/WebSocket/AgentThinkingResponse.cs (2)
9-11
: Fix incorrect XML documentation.The XML comment for the
Type
property incorrectly mentions "SettingsConfiguration" instead of "AgentThinking".- /// SettingsConfiguration event type. + /// The type of the agent event, which is AgentThinking.
17-19
: Add XML documentation for the Content property.Missing XML documentation for the
Content
property.+ /// <summary> + /// The content of the agent's thinking response. + /// </summary> [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]Deepgram/Models/Agent/v2/WebSocket/Agent.cs (3)
9-11
: Add XML documentation for the Listen property.Missing XML documentation for the
Listen
property.+ /// <summary> + /// Configuration for the agent's listening capabilities. + /// </summary> [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
13-15
: Add XML documentation for the Think property.Missing XML documentation for the
Think
property.+ /// <summary> + /// Configuration for the agent's thinking capabilities. + /// </summary> [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
17-19
: Add XML documentation for the Speak property.Missing XML documentation for the
Speak
property.+ /// <summary> + /// Configuration for the agent's speaking capabilities. + /// </summary> [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]Deepgram/Models/Agent/v2/WebSocket/FunctionCallingResponse.cs (2)
9-11
: Fix incorrect XML documentation.The XML comment for the
Type
property incorrectly mentions "SettingsConfiguration" instead of "FunctionCalling".- /// SettingsConfiguration event type. + /// The type of the agent event, which is FunctionCalling.
17-19
: Add XML documentation for the SessionId property.Missing XML documentation for the
SessionId
property.+ /// <summary> + /// The unique identifier for the current session. + /// </summary> [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]Deepgram/Models/Agent/v2/WebSocket/Parameters.cs (3)
13-15
: Add XML documentation for the Properties property.Missing XML documentation for the
Properties
property.+ /// <summary> + /// The properties configuration for the parameters. + /// </summary> [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
17-19
: Add XML documentation for the ParametersRequired property.Missing XML documentation for the
ParametersRequired
property.+ /// <summary> + /// The list of required parameter names. + /// </summary> [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
21-22
: Remove extra blank lines.There are two consecutive blank lines between properties and the ToString method.
public List<string>? ParametersRequired { get; set; } - - /// <summary>Deepgram/Models/Agent/v2/WebSocket/AudioResponse.cs (2)
7-30
: Add XML documentation for the Dispose method.The class has good documentation overall, but the
Dispose
method is missing XML documentation. Consider adding it to maintain consistency.+ /// <summary> + /// Disposes of the underlying stream if it exists. + /// </summary> public void Dispose() { Stream?.Dispose(); Stream = null; }
22-23
: Consider formalizing the note about ToString().The note about ToString() could be more formal using XML documentation.
- // NOTE: There isn't a ToString() function because this will cause an odd Exception to be thrown: - // InvalidOperationException: "Timeouts are not supported on this stream." + /// <summary> + /// ToString() is intentionally not overridden as it would cause an InvalidOperationException + /// with the message "Timeouts are not supported on this stream." + /// </summary>Deepgram/Models/Agent/v2/WebSocket/FunctionCallResponseSchema.cs (3)
9-11
: Fix incorrect XML documentation.The documentation for the
Type
property incorrectly states "SettingsConfiguration event type" when it should describe the function call response type./// <summary> - /// SettingsConfiguration event type. + /// The type of the function call response. /// </summary>
16-22
: Add XML documentation for missing properties.The
FunctionCallId
andOutput
properties are missing XML documentation.+ /// <summary> + /// The unique identifier of the function call. + /// </summary> [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("function_call_id")] public string? FunctionCallId { get; set; } + /// <summary> + /// The output returned by the function call. + /// </summary> [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("output")] public string? Output { get; set; }
7-31
: Consider using a record for immutability.Since this class represents a response schema, consider making it immutable by converting it to a record with init-only properties.
-public class FunctionCallResponseSchema +public record FunctionCallResponseSchema { [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("type")] - public string? Type { get; } = AgentClientTypes.FunctionCallResponse; + public string? Type { get; init; } = AgentClientTypes.FunctionCallResponse; [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("function_call_id")] - public string? FunctionCallId { get; set; } + public string? FunctionCallId { get; init; } [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("output")] - public string? Output { get; set; } + public string? Output { get; init; }Deepgram/Models/Agent/v2/WebSocket/ConversationTextResponse.cs (3)
9-11
: Fix incorrect XML documentation.The documentation for the
Type
property incorrectly states "SettingsConfiguration event type" when it should describe the conversation text type./// <summary> - /// SettingsConfiguration event type. + /// The type of the conversation text response. /// </summary>
17-23
: Add XML documentation for missing properties.The
Role
andContent
properties are missing XML documentation.+ /// <summary> + /// The role of the conversation participant (e.g., user, assistant). + /// </summary> [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("role")] public string? Role { get; set; } + /// <summary> + /// The content of the conversation message. + /// </summary> [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("content")] public string? Content { get; set; }
7-32
: Consider using init-only properties.Since this is already a record, consider making the properties init-only for better immutability.
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("role")] - public string? Role { get; set; } + public string? Role { get; init; } [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("content")] - public string? Content { get; set; } + public string? Content { get; init; }Deepgram/Models/Agent/v2/WebSocket/Think.cs (3)
9-23
: Add XML documentation for all properties.All properties are missing XML documentation.
+ /// <summary> + /// The provider configuration for the think operation. + /// </summary> [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("provider")] public Provider? Provider { get; set; } = new Provider(); + /// <summary> + /// The model to be used for thinking. + /// </summary> [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("model")] public string? Model { get; set; } + /// <summary> + /// The instructions for the think operation. + /// </summary> [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("instructions")] public string? Instructions { get; set; } + /// <summary> + /// The list of functions available during the think operation. + /// </summary> [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("functions")] public List<Function>? Functions { get; set; }
25-26
: Remove unnecessary blank lines.There are two consecutive blank lines that should be removed.
public List<Function>? Functions { get; set; } - - /// <summary>
7-34
: Consider using init-only properties.Since this is a record, consider making the properties init-only for better immutability.
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("provider")] - public Provider? Provider { get; set; } = new Provider(); + public Provider? Provider { get; init; } = new Provider(); [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("model")] - public string? Model { get; set; } + public string? Model { get; init; } [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("instructions")] - public string? Instructions { get; set; } + public string? Instructions { get; init; } [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("functions")] - public List<Function>? Functions { get; set; } + public List<Function>? Functions { get; init; }Deepgram/Models/Agent/v2/WebSocket/SettingsConfigurationSchema.cs (2)
16-26
: Add XML documentation for public properties.The
Audio
,Agent
, andContext
properties are missing XML documentation. Adding documentation would improve API usability and maintain consistency with other documented members.
31-34
: Consider optimizing ToString() implementation.The current implementation uses
Regex.Unescape
which might be unnecessary overhead if the serialized JSON doesn't contain escaped characters. Consider usingJsonSerializer.Serialize
directly unless there's a specific need for unescaping.- return Regex.Unescape(JsonSerializer.Serialize(this, JsonSerializeOptions.DefaultOptions)); + return JsonSerializer.Serialize(this, JsonSerializeOptions.DefaultOptions);Deepgram/Models/Agent/v2/WebSocket/AgentStartedSpeakingResponse.cs (1)
9-11
: Fix incorrect XML documentation.The XML documentation for the
Type
property incorrectly states "SettingsConfiguration event type" when it should describe the agent started speaking event type.- /// SettingsConfiguration event type. + /// The type of the event, indicating that the agent has started speaking.Deepgram/Clients/Interfaces/v2/IAgentWebSocketClient.cs (1)
121-133
: Clarify the distinction between binary and text messages.The documentation doesn't clearly explain the difference between
SendBinary
andSendMessage
. Both accept byte arrays but their purposes seem different. Consider adding detailed documentation about when to use each method.examples/agent/websocket/simple/Program.cs (2)
47-47
: Extract magic number to constant.The hardcoded value
7
should be extracted to a named constant for better maintainability.+private const int AUDIO_FILE_TIMEOUT_SECONDS = 7; -if (DateTime.Now.Subtract(lastAudioTime).TotalSeconds > 7) +if (DateTime.Now.Subtract(lastAudioTime).TotalSeconds > AUDIO_FILE_TIMEOUT_SECONDS)
210-218
: Enhance cleanup error handling.While resources are properly disposed, the error handling could be more robust.
-// Stop the microphone -microphone.Stop(); +try +{ + Console.WriteLine("Stopping microphone..."); + microphone.Stop(); + + Console.WriteLine("Stopping WebSocket connection..."); + await agentClient.Stop(); + + Console.WriteLine("Terminating libraries..."); + Deepgram.Microphone.Library.Terminate(); + Deepgram.Library.Terminate(); + + Console.WriteLine("Cleanup completed successfully"); +} +catch (Exception ex) +{ + Console.WriteLine($"Error during cleanup: {ex.Message}"); + // Consider logging to file or telemetry service +}
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (50)
Deepgram.Dev.sln
(3 hunks)Deepgram/AgentWebSocketClient.cs
(1 hunks)Deepgram/ClientFactory.cs
(2 hunks)Deepgram/Clients/Agent/v2/Websocket/Client.cs
(1 hunks)Deepgram/Clients/Agent/v2/Websocket/Constants.cs
(1 hunks)Deepgram/Clients/Agent/v2/Websocket/ResponseEvent.cs
(1 hunks)Deepgram/Clients/Agent/v2/Websocket/UriSegments.cs
(1 hunks)Deepgram/Clients/Interfaces/v2/IAgentWebSocketClient.cs
(1 hunks)Deepgram/Deepgram.csproj
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/Agent.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/AgentAudioDoneResponse.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/AgentStartedSpeakingResponse.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/AgentThinkingResponse.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/AgentType.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/Audio.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/AudioResponse.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/CloseResponse.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/Context.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/ControlMessage.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/ConversationTextResponse.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/ErrorResponse.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/Function.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/FunctionCallRequestResponse.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/FunctionCallResponseSchema.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/FunctionCallingResponse.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/Header.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/InjectAgentMessageSchema.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/InjectionRefusedResponse.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/Input.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/InstructionsUpdatedResponse.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/Item.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/KeepAliveSchema.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/Listen.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/OpenResponse.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/Output.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/Parameters.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/Properties.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/Provider.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/SettingsAppliedResponse.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/SettingsConfigurationSchema.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/Speak.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/SpeakUpdatedResponse.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/Think.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/UnhandledResponse.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/UpdateInstructionsSchema.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/UpdateSpeakSchema.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/UserStartedSpeakingResponse.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/WelcomeResponse.cs
(1 hunks)examples/agent/websocket/simple/Agent.csproj
(1 hunks)examples/agent/websocket/simple/Program.cs
(1 hunks)
✅ Files skipped from review due to trivial changes (6)
- examples/agent/websocket/simple/Agent.csproj
- Deepgram/Models/Agent/v2/WebSocket/OpenResponse.cs
- Deepgram/Models/Agent/v2/WebSocket/ErrorResponse.cs
- Deepgram/Clients/Agent/v2/Websocket/Constants.cs
- Deepgram/Models/Agent/v2/WebSocket/CloseResponse.cs
- Deepgram/Models/Agent/v2/WebSocket/UnhandledResponse.cs
🧰 Additional context used
📓 Learnings (2)
Deepgram/Models/Agent/v2/WebSocket/ControlMessage.cs (1)
Learnt from: dvonthenen
PR: deepgram/deepgram-dotnet-sdk#316
File: Deepgram/Models/Speak/v1/WebSocket/ControlMessage.cs:7-8
Timestamp: 2024-11-12T11:33:12.821Z
Learning: Primary constructor syntax in class declarations, such as `public class ClassName(Type parameter)`, is valid starting from C# 12.
Deepgram/ClientFactory.cs (1)
Learnt from: dvonthenen
PR: deepgram/deepgram-dotnet-sdk#347
File: Deepgram/ClientFactory.cs:146-161
Timestamp: 2024-11-12T11:33:27.266Z
Learning: In `Deepgram/ClientFactory.cs`, the method `CreateListenWebSocketClient(int version, ...)` is intentionally returning `object` as a placeholder because there is only one version of the client. It should not be suggested to change the return type until multiple versions are implemented.
🪛 GitHub Actions: CI
Deepgram/Deepgram.csproj
[warning] Package 'System.Text.Json' 7.0.4 has a known high severity vulnerability, see: GHSA-hh2w-p6rv-4g7w
🔇 Additional comments (26)
Deepgram/Models/Agent/v2/WebSocket/UserStartedSpeakingResponse.cs (1)
1-5
: LGTM! Well-structured file header.The file includes proper copyright notice, license reference, and follows the correct namespace hierarchy.
Deepgram/Models/Agent/v2/WebSocket/InstructionsUpdatedResponse.cs (2)
1-4
: LGTM! Well-structured license header.The license header follows best practices by including copyright notice, license reference, and SPDX identifier.
5-5
: LGTM! Properly structured namespace.The namespace follows .NET conventions and matches the physical file structure.
Deepgram/Models/Agent/v2/WebSocket/AgentType.cs (2)
1-8
: LGTM! Well-structured file header and namespace organization.The file follows .NET conventions with proper license headers and namespace organization.
30-40
: Add XML documentation and verify message type consistency.The static class could benefit from better documentation and validation:
- Add XML documentation for the class and constants.
- Clarify the purpose of these message types in the comments.
Here's a suggested implementation:
+/// <summary> +/// Defines the message types that can be sent by the client to the agent WebSocket API. +/// </summary> public static class AgentClientTypes { - // user message types + // Client-to-agent message types for configuration and control /// <summary> /// Message type for configuring agent settings. /// </summary> public const string SettingsConfiguration = "SettingsConfiguration"; // Add similar XML docs for other constants }Let's verify that these message types match the API schema:
✅ Verification successful
Message types are well-defined and consistently used
The message types are properly integrated into the codebase with corresponding schema files and response models. Each constant has matching implementations in:
- Schema files (e.g.,
SettingsConfigurationSchema.cs
)- Response models (e.g.,
SettingsAppliedResponse.cs
)- Client implementations across different versions
While XML documentation would improve the API's usability, the message types themselves are well-structured and consistently used.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Search for references to these message types in request/response models # and schema definitions to ensure consistency. echo "Searching for message type usage in models and schemas..." rg -l "SettingsConfiguration|UpdateInstructions|UpdateSpeak|InjectAgentMessage|FunctionCallResponse|KeepAlive" \ --type cs echo -e "\nSearching for potential message type definitions in other files..." rg -i "(?:const|static).*(message.*type|type.*message)" \ --type csLength of output: 2391
Deepgram/Models/Agent/v2/WebSocket/Audio.cs (1)
18-24
: Add null check in ToString() implementation.The current implementation might throw NullReferenceException if JsonSerializeOptions.DefaultOptions is null.
Deepgram/Models/Agent/v2/WebSocket/Output.cs (2)
25-31
: Add null check in ToString() implementation.Similar to Audio.cs, the ToString implementation needs a null check for JsonSerializeOptions.DefaultOptions.
1-32
: Add unit tests for the Output record.The PR objectives mention that tests haven't been added yet. Consider adding unit tests to verify:
- Default value initialization
- JSON serialization/deserialization
- Null handling
- ToString() behavior
Would you like me to generate the unit test code?
Deepgram/Clients/Agent/v2/Websocket/Client.cs (2)
449-480
: Consider using built-in CloseAsync or providing a WebSocket close status.
CallingSendAsync
with a single null byte is an unorthodox way to close the connection. Usually,CloseAsync
is used with a standard close status code. This approach may limit the ability to convey a proper close reason to the server or logs. Evaluate whether you can leverage the built-in close mechanism.
75-103
: Ensure safe keep-alive lifecycle management.
Starting the keep-alive loop in a background thread without storing a reference or controlling when it should stop can create concurrency issues if the connection is closed soon after callingConnect
. Consider tracking the loop’sTask
so you can wait on it during shutdown or forcibly end it if errors occur.Deepgram/Models/Agent/v2/WebSocket/Item.cs (1)
20-23
: Consider removing Regex.Unescape from ToString.The
Regex.Unescape
might not be necessary asJsonSerializer
already handles proper JSON string escaping. This could potentially cause issues with valid JSON strings that contain escape sequences.- return Regex.Unescape(JsonSerializer.Serialize(this, JsonSerializeOptions.DefaultOptions)); + return JsonSerializer.Serialize(this, JsonSerializeOptions.DefaultOptions);Deepgram/Models/Agent/v2/WebSocket/Context.cs (1)
21-24
: Consider removing Regex.Unescape from ToString.Similar to Item.cs, the
Regex.Unescape
might not be necessary and could potentially cause issues.- return Regex.Unescape(JsonSerializer.Serialize(this, JsonSerializeOptions.DefaultOptions)); + return JsonSerializer.Serialize(this, JsonSerializeOptions.DefaultOptions);✅ Verification successful
Remove Regex.Unescape from ToString() in Content.cs
The Regex.Unescape is unnecessary as the properties don't contain special characters requiring unescaping. JsonSerializer.Serialize already handles proper JSON escaping. Note: The review mentions Context.cs but the file is actually Content.cs.
- return Regex.Unescape(JsonSerializer.Serialize(this, JsonSerializeOptions.DefaultOptions)); + return JsonSerializer.Serialize(this, JsonSerializeOptions.DefaultOptions);🏁 Scripts executed
The following scripts were executed for the analysis:
Error: No shell scripts found
Script:
#!/bin/bash # Find and show the complete Context.cs file fd Context.cs | grep -i "websocket" | xargs cat # Find and show Item.cs for comparison fd Item.cs | grep -i "deepgram" | xargs cat # Look for test files related to Context fd "Context.*Test.*\.cs$" # Search for usages of Context.ToString() rg -l "Context.*ToString" --type csLength of output: 1763
Deepgram/Models/Agent/v2/WebSocket/SpeakUpdatedResponse.cs (1)
20-23
: Consider removing Regex.Unescape from ToString.Similar to other response classes, the
Regex.Unescape
might not be necessary and could potentially cause issues.- return Regex.Unescape(JsonSerializer.Serialize(this, JsonSerializeOptions.DefaultOptions)); + return JsonSerializer.Serialize(this, JsonSerializeOptions.DefaultOptions);Deepgram/Models/Agent/v2/WebSocket/AgentAudioDoneResponse.cs (1)
20-23
: Consider removing Regex.Unescape from ToString.Similar to other response classes, the
Regex.Unescape
might not be necessary and could potentially cause issues.- return Regex.Unescape(JsonSerializer.Serialize(this, JsonSerializeOptions.DefaultOptions)); + return JsonSerializer.Serialize(this, JsonSerializeOptions.DefaultOptions);Deepgram/Models/Agent/v2/WebSocket/InjectAgentMessageSchema.cs (2)
9-14
: Fix incorrect XML documentation for Type propertySame issue as in UpdateSpeakSchema: The XML comment incorrectly states "SettingsConfiguration event type".
23-26
: Add error handling to ToString methodSame issue as in UpdateSpeakSchema: The ToString method should handle potential serialization errors.
Deepgram/Models/Agent/v2/WebSocket/UpdateInstructionsSchema.cs (2)
9-14
: Fix incorrect XML documentation for Type propertySame issue as in previous schemas: The XML comment incorrectly states "SettingsConfiguration event type".
23-26
: Add error handling to ToString methodSame issue as in previous schemas: The ToString method should handle potential serialization errors.
Deepgram/Models/Agent/v2/WebSocket/WelcomeResponse.cs (3)
7-8
: LGTM! Good use of record typeUsing a record type is appropriate for this response object as it promotes immutability and provides value-based equality.
9-15
: Fix incorrect XML documentation for Type propertySame issue as in previous schemas: The XML comment incorrectly states "SettingsConfiguration event type".
24-27
: Add error handling to ToString methodSame issue as in previous schemas: The ToString method should handle potential serialization errors.
Deepgram/Models/Agent/v2/WebSocket/Parameters.cs (1)
9-11
: Add XML documentation and consider making Type nullable.The
Type
property is missing XML documentation and is not nullable despite having no default value.+ /// <summary> + /// The type of the parameters. + /// </summary> [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("type")] - public string Type { get; set; } + public string? Type { get; set; }Let's verify if the
Type
property can be null in the API response:Deepgram/Clients/Interfaces/v2/IAgentWebSocketClient.cs (1)
126-133
: Consider thread safety for non-async send methods.The
SendBinary
andSendMessage
methods are not async and don't accept cancellation tokens, which could lead to thread safety issues in a concurrent environment. Consider making them async or documenting thread safety guarantees.Deepgram/ClientFactory.cs (1)
18-27
: LGTM! The implementation follows the established pattern.The new agent client factory methods are consistent with the existing codebase structure and patterns.
Deepgram.Dev.sln (1)
180-187
: LGTM! Well-structured project organization.The new agent-related projects are properly organized in the solution hierarchy with appropriate GUIDs and configurations.
Also applies to: 427-430
Deepgram/Deepgram.csproj (1)
127-131
: LGTM! Clean removal of v1 agent models.The removal of v1 agent models is appropriate as part of the transition to v2 implementation.
🧰 Tools
🪛 GitHub Actions: CI
[warning] Package 'System.Text.Json' 7.0.4 has a known high severity vulnerability, see: GHSA-hh2w-p6rv-4g7w
public record UserStartedSpeakingResponse | ||
{ | ||
/// <summary> | ||
/// SettingsConfiguration event type. | ||
/// </summary> | ||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] | ||
[JsonPropertyName("type")] | ||
[JsonConverter(typeof(JsonStringEnumConverter))] | ||
public AgentType? Type { get; } = AgentType.UserStartedSpeaking; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add proper documentation and consider property design.
- The XML documentation for the
Type
property appears to be incorrect (mentions "SettingsConfiguration"). - Consider adding XML documentation for the record class itself.
- Since
Type
has a default value ofAgentType.UserStartedSpeaking
, making it nullable might be unnecessary.
Apply these changes:
+/// <summary>
+/// Represents a response indicating that a user has started speaking in an agent conversation.
+/// </summary>
public record UserStartedSpeakingResponse
{
/// <summary>
- /// SettingsConfiguration event type.
+ /// The type of agent event, which is always UserStartedSpeaking for this response.
/// </summary>
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[JsonPropertyName("type")]
[JsonConverter(typeof(JsonStringEnumConverter))]
- public AgentType? Type { get; } = AgentType.UserStartedSpeaking;
+ public AgentType Type { get; } = AgentType.UserStartedSpeaking;
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
public record UserStartedSpeakingResponse | |
{ | |
/// <summary> | |
/// SettingsConfiguration event type. | |
/// </summary> | |
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] | |
[JsonPropertyName("type")] | |
[JsonConverter(typeof(JsonStringEnumConverter))] | |
public AgentType? Type { get; } = AgentType.UserStartedSpeaking; | |
/// <summary> | |
/// Represents a response indicating that a user has started speaking in an agent conversation. | |
/// </summary> | |
public record UserStartedSpeakingResponse | |
{ | |
/// <summary> | |
/// The type of agent event, which is always UserStartedSpeaking for this response. | |
/// </summary> | |
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] | |
[JsonPropertyName("type")] | |
[JsonConverter(typeof(JsonStringEnumConverter))] | |
public AgentType Type { get; } = AgentType.UserStartedSpeaking; |
/// <summary> | ||
/// Override ToString method to serialize the object | ||
/// </summary> | ||
public override string ToString() | ||
{ | ||
return Regex.Unescape(JsonSerializer.Serialize(this, JsonSerializeOptions.DefaultOptions)); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Improve ToString implementation and documentation.
- Missing using directives for required types.
- Using
Regex.Unescape
might be unnecessary and could potentially cause issues with valid JSON strings. - Incomplete XML documentation.
Apply these changes:
+using System.Text.Json;
+using System.Text.RegularExpressions;
/// <summary>
- /// Override ToString method to serialize the object
+ /// Converts the current object to its JSON string representation.
/// </summary>
+ /// <returns>A JSON string representation of the current object.</returns>
public override string ToString()
{
- return Regex.Unescape(JsonSerializer.Serialize(this, JsonSerializeOptions.DefaultOptions));
+ return JsonSerializer.Serialize(this, JsonSerializeOptions.DefaultOptions);
}
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
/// <summary> | |
/// Override ToString method to serialize the object | |
/// </summary> | |
public override string ToString() | |
{ | |
return Regex.Unescape(JsonSerializer.Serialize(this, JsonSerializeOptions.DefaultOptions)); | |
} | |
using System.Text.Json; | |
using System.Text.RegularExpressions; | |
/// <summary> | |
/// Converts the current object to its JSON string representation. | |
/// </summary> | |
/// <returns>A JSON string representation of the current object.</returns> | |
public override string ToString() | |
{ | |
return JsonSerializer.Serialize(this, JsonSerializeOptions.DefaultOptions); | |
} |
public record InstructionsUpdatedResponse | ||
{ | ||
/// <summary> | ||
/// SettingsConfiguration event type. | ||
/// </summary> | ||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] | ||
[JsonPropertyName("type")] | ||
[JsonConverter(typeof(JsonStringEnumConverter))] | ||
public AgentType? Type { get; } = AgentType.InstructionsUpdated; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Fix documentation and property nullability.
- The XML documentation for the Type property is incorrect (mentions "SettingsConfiguration" instead of "Instructions Updated").
- Missing XML documentation for the record class itself.
- The Type property could be non-nullable since it has a default value.
Apply these changes:
+/// <summary>
+/// Represents a response indicating that agent instructions have been updated.
+/// </summary>
public record InstructionsUpdatedResponse
{
/// <summary>
- /// SettingsConfiguration event type.
+ /// The type of agent event, which is always InstructionsUpdated.
/// </summary>
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[JsonPropertyName("type")]
[JsonConverter(typeof(JsonStringEnumConverter))]
- public AgentType? Type { get; } = AgentType.InstructionsUpdated;
+ public AgentType Type { get; } = AgentType.InstructionsUpdated;
}
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
public record InstructionsUpdatedResponse | |
{ | |
/// <summary> | |
/// SettingsConfiguration event type. | |
/// </summary> | |
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] | |
[JsonPropertyName("type")] | |
[JsonConverter(typeof(JsonStringEnumConverter))] | |
public AgentType? Type { get; } = AgentType.InstructionsUpdated; | |
/// <summary> | |
/// Represents a response indicating that agent instructions have been updated. | |
/// </summary> | |
public record InstructionsUpdatedResponse | |
{ | |
/// <summary> | |
/// The type of agent event, which is always InstructionsUpdated. | |
/// </summary> | |
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] | |
[JsonPropertyName("type")] | |
[JsonConverter(typeof(JsonStringEnumConverter))] | |
public AgentType Type { get; } = AgentType.InstructionsUpdated; |
public async Task<bool> Connect(SettingsConfigurationSchema options, CancellationTokenSource? cancelToken = null, Dictionary<string, string>? addons = null, | ||
Dictionary<string, string>? headers = null) | ||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Use a CancellationToken parameter instead of CancellationTokenSource.
Passing a CancellationTokenSource
to the Connect
method exposes lower-level management details to callers. Typically, methods accept a CancellationToken
, allowing the caller to manage the CancellationTokenSource
more flexibly and handle cancellation at a higher level.
-public async Task<bool> Connect(SettingsConfigurationSchema options, CancellationTokenSource? cancelToken = null, Dictionary<string, string>? addons = null,
- Dictionary<string, string>? headers = null)
+public async Task<bool> Connect(
+ SettingsConfigurationSchema options,
+ CancellationToken cancelToken = default,
+ Dictionary<string, string>? addons = null,
+ Dictionary<string, string>? headers = null)
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
public async Task<bool> Connect(SettingsConfigurationSchema options, CancellationTokenSource? cancelToken = null, Dictionary<string, string>? addons = null, | |
Dictionary<string, string>? headers = null) | |
{ | |
public async Task<bool> Connect( | |
SettingsConfigurationSchema options, | |
CancellationToken cancelToken = default, | |
Dictionary<string, string>? addons = null, | |
Dictionary<string, string>? headers = null) | |
{ |
public class ControlMessage(string text) | ||
{ | ||
/// <summary> | ||
/// Gets or sets the type of control message. | ||
/// </summary> | ||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] | ||
[JsonPropertyName("type")] | ||
public string? Type { get; set; } = text; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Consider using a record and add parameter validation.
- Add validation for the
text
parameter - Consider making this a record with init-only property
- Add XML documentation for the constructor
- public class ControlMessage(string text)
+ /// <summary>
+ /// Represents a control message in the WebSocket communication.
+ /// </summary>
+ /// <param name="text">The type of control message. Cannot be null.</param>
+ /// <exception cref="ArgumentNullException">Thrown when text is null.</exception>
+ public record ControlMessage
{
+ public ControlMessage(string text)
+ {
+ ArgumentNullException.ThrowIfNull(text);
+ Type = text;
+ }
+
/// <summary>
/// Gets or sets the type of control message.
/// </summary>
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
[JsonPropertyName("type")]
- public string? Type { get; set; } = text;
+ public string? Type { get; init; }
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
public class ControlMessage(string text) | |
{ | |
/// <summary> | |
/// Gets or sets the type of control message. | |
/// </summary> | |
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] | |
[JsonPropertyName("type")] | |
public string? Type { get; set; } = text; | |
/// <summary> | |
/// Represents a control message in the WebSocket communication. | |
/// </summary> | |
/// <param name="text">The type of control message. Cannot be null.</param> | |
/// <exception cref="ArgumentNullException">Thrown when text is null.</exception> | |
public record ControlMessage | |
{ | |
public ControlMessage(string text) | |
{ | |
ArgumentNullException.ThrowIfNull(text); | |
Type = text; | |
} | |
/// <summary> | |
/// Gets or sets the type of control message. | |
/// </summary> | |
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] | |
[JsonPropertyName("type")] | |
public string? Type { get; init; } |
await agentClient.Subscribe(new EventHandler<AgentAudioDoneResponse>((sender, e) => | ||
{ | ||
Console.WriteLine($"----> {e} received"); | ||
})); | ||
await agentClient.Subscribe(new EventHandler<AgentStartedSpeakingResponse>((sender, e) => | ||
{ | ||
Console.WriteLine($"----> {e} received"); | ||
})); | ||
await agentClient.Subscribe(new EventHandler<AgentThinkingResponse>((sender, e) => | ||
{ | ||
Console.WriteLine($"----> {e} received"); | ||
})); | ||
await agentClient.Subscribe(new EventHandler<ConversationTextResponse>((sender, e) => | ||
{ | ||
Console.WriteLine($"----> {e} received"); | ||
})); | ||
await agentClient.Subscribe(new EventHandler<FunctionCallingResponse>((sender, e) => | ||
{ | ||
Console.WriteLine($"----> {e} received"); | ||
})); | ||
await agentClient.Subscribe(new EventHandler<FunctionCallRequestResponse>((sender, e) => | ||
{ | ||
Console.WriteLine($"----> {e} received"); | ||
})); | ||
await agentClient.Subscribe(new EventHandler<UserStartedSpeakingResponse>((sender, e) => | ||
{ | ||
Console.WriteLine($"----> {e} received"); | ||
})); | ||
await agentClient.Subscribe(new EventHandler<WelcomeResponse>((sender, e) => | ||
{ | ||
Console.WriteLine($"----> {e} received"); | ||
})); | ||
await agentClient.Subscribe(new EventHandler<CloseResponse>((sender, e) => | ||
{ | ||
Console.WriteLine($"----> {e} received"); | ||
})); | ||
await agentClient.Subscribe(new EventHandler<SettingsAppliedResponse>((sender, e) => | ||
{ | ||
Console.WriteLine($"----> {e} received"); | ||
})); | ||
await agentClient.Subscribe(new EventHandler<InjectionRefusedResponse>((sender, e) => | ||
{ | ||
Console.WriteLine($"----> {e} received"); | ||
})); | ||
await agentClient.Subscribe(new EventHandler<InstructionsUpdatedResponse>((sender, e) => | ||
{ | ||
Console.WriteLine($"----> {e} received"); | ||
})); | ||
await agentClient.Subscribe(new EventHandler<SpeakUpdatedResponse>((sender, e) => | ||
{ | ||
Console.WriteLine($"----> {e} received."); | ||
})); | ||
await agentClient.Subscribe(new EventHandler<UnhandledResponse>((sender, e) => | ||
{ | ||
Console.WriteLine($"----> {e} received"); | ||
})); | ||
await agentClient.Subscribe(new EventHandler<ErrorResponse>((sender, e) => | ||
{ | ||
Console.WriteLine($"----> {e} received. Error: {e.Message}"); | ||
})); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Enhance event handlers with proper error handling and logging.
The current event handlers only log the event type. Consider adding:
- Proper error handling
- Detailed logging of event data
- Retry logic for recoverable errors
Example enhancement for one handler:
await agentClient.Subscribe(new EventHandler<AgentAudioDoneResponse>((sender, e) =>
{
- Console.WriteLine($"----> {e} received");
+ try
+ {
+ Console.WriteLine($"----> Agent audio done event received");
+ Console.WriteLine($" Duration: {e.Duration}");
+ Console.WriteLine($" Status: {e.Status}");
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Error handling agent audio done event: {ex.Message}");
+ }
}));
Committable suggestion skipped: line range outside the PR's diff.
bool bConnected = await agentClient.Connect(settingsConfiguration); | ||
if (!bConnected) | ||
{ | ||
Console.WriteLine("Failed to connect to Deepgram WebSocket server."); | ||
return; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Enhance connection error handling.
The connection failure handling is minimal. Consider adding retry logic and more detailed error information.
-bool bConnected = await agentClient.Connect(settingsConfiguration);
-if (!bConnected)
-{
- Console.WriteLine("Failed to connect to Deepgram WebSocket server.");
- return;
-}
+int maxRetries = 3;
+for (int i = 0; i < maxRetries; i++)
+{
+ try
+ {
+ bool bConnected = await agentClient.Connect(settingsConfiguration);
+ if (bConnected)
+ {
+ Console.WriteLine("Successfully connected to Deepgram WebSocket server.");
+ break;
+ }
+
+ if (i == maxRetries - 1)
+ {
+ throw new Exception("Maximum retry attempts reached");
+ }
+
+ Console.WriteLine($"Connection attempt {i + 1} failed, retrying...");
+ await Task.Delay(1000 * (i + 1)); // Exponential backoff
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"Failed to connect: {ex.Message}");
+ return;
+ }
+}
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
bool bConnected = await agentClient.Connect(settingsConfiguration); | |
if (!bConnected) | |
{ | |
Console.WriteLine("Failed to connect to Deepgram WebSocket server."); | |
return; | |
} | |
int maxRetries = 3; | |
for (int i = 0; i < maxRetries; i++) | |
{ | |
try | |
{ | |
bool bConnected = await agentClient.Connect(settingsConfiguration); | |
if (bConnected) | |
{ | |
Console.WriteLine("Successfully connected to Deepgram WebSocket server."); | |
break; | |
} | |
if (i == maxRetries - 1) | |
{ | |
throw new Exception("Maximum retry attempts reached"); | |
} | |
Console.WriteLine($"Connection attempt {i + 1} failed, retrying..."); | |
await Task.Delay(1000 * (i + 1)); // Exponential backoff | |
} | |
catch (Exception ex) | |
{ | |
Console.WriteLine($"Failed to connect: {ex.Message}"); | |
return; | |
} | |
} |
// delete the file if it exists | ||
if (File.Exists($"output_{audioFileCount}.wav")) | ||
{ | ||
File.Delete($"output_{audioFileCount}.wav"); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add directory cleanup and exception handling for file operations.
File operations should be wrapped in try-catch blocks and old files should be cleaned up.
+try
+{
+ // Clean up old files
+ var oldFiles = Directory.GetFiles(".", "output_*.wav");
+ foreach (var file in oldFiles.OrderByDescending(f => f))
+ {
+ if (int.Parse(Path.GetFileNameWithoutExtension(file).Split('_')[1]) < audioFileCount - 5)
+ {
+ File.Delete(file);
+ }
+ }
+
// delete the file if it exists
if (File.Exists($"output_{audioFileCount}.wav"))
{
File.Delete($"output_{audioFileCount}.wav");
}
+}
+catch (Exception ex)
+{
+ Console.WriteLine($"Error managing audio files: {ex.Message}");
+}
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
// delete the file if it exists | |
if (File.Exists($"output_{audioFileCount}.wav")) | |
{ | |
File.Delete($"output_{audioFileCount}.wav"); | |
} | |
try | |
{ | |
// Clean up old files | |
var oldFiles = Directory.GetFiles(".", "output_*.wav"); | |
foreach (var file in oldFiles.OrderByDescending(f => f)) | |
{ | |
if (int.Parse(Path.GetFileNameWithoutExtension(file).Split('_')[1]) < audioFileCount - 5) | |
{ | |
File.Delete(file); | |
} | |
} | |
// delete the file if it exists | |
if (File.Exists($"output_{audioFileCount}.wav")) | |
{ | |
File.Delete($"output_{audioFileCount}.wav"); | |
} | |
} | |
catch (Exception ex) | |
{ | |
Console.WriteLine($"Error managing audio files: {ex.Message}"); | |
} |
// Start the connection | ||
var settingsConfiguration = new SettingsConfigurationSchema(); | ||
settingsConfiguration.Agent.Think.Provider.Type = "open_ai"; | ||
settingsConfiguration.Agent.Think.Model = "gpt-4o-mini"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Codebase verification
Invalid OpenAI model name "gpt-4o-mini"
The model name appears to be a typo. OpenAI doesn't have a model named "gpt-4o-mini". The standard OpenAI model names follow patterns like "gpt-4", "gpt-4-turbo", or "gpt-3.5-turbo". This will cause runtime errors when attempting to use the OpenAI provider.
🔗 Analysis chain
Verify the model name "gpt-4o-mini".
The model name appears to be incorrect. Verify if this is a typo or if this model actually exists.
Run this script to check available models:
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check if the model exists in the codebase or documentation
rg -i "gpt-4o-mini"
Length of output: 135
Script:
#!/bin/bash
# Search for model configurations in the codebase
rg -i "model.*=.*gpt" -A 1 -B 1
Length of output: 412
@@ -123,6 +123,12 @@ | |||
<PackageReference Include="System.Text.Json" Version="8.*" /> | |||
<PackageReference Include="System.Threading.Channels" Version="8.*" /> | |||
</ItemGroup> | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Address high severity vulnerability in System.Text.Json package.
The pipeline detected a high severity vulnerability in System.Text.Json 7.0.4.
Update the package references to use patched versions:
- <PackageReference Include="System.Text.Json" Version="7.*" />
+ <PackageReference Include="System.Text.Json" Version="7.0.5" />
Committable suggestion skipped: line range outside the PR's diff.
🧰 Tools
🪛 GitHub Actions: CI
[warning] Package 'System.Text.Json' 7.0.4 has a known high severity vulnerability, see: GHSA-hh2w-p6rv-4g7w
23e95af
to
fba9367
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
♻️ Duplicate comments (5)
examples/agent/websocket/simple/Program.cs (5)
30-31
:⚠️ Potential issueAdd API key validation and error handling.
The code passes an empty API key to
CreateAgentWebSocketClient
. This will cause runtime issues.
51-55
: 🛠️ Refactor suggestionAdd directory cleanup and exception handling for file operations.
File operations should be wrapped in try-catch blocks and old files should be cleaned up.
127-186
: 🛠️ Refactor suggestionEnhance event handlers with proper error handling and logging.
The current event handlers only log the event type. Consider adding proper error handling, detailed logging of event data, and retry logic for recoverable errors.
191-191
:⚠️ Potential issueInvalid OpenAI model name "gpt-4o-mini".
The model name appears to be a typo. OpenAI doesn't have a model named "gpt-4o-mini".
196-201
: 🛠️ Refactor suggestionEnhance connection error handling.
The connection failure handling is minimal. Consider adding retry logic and more detailed error information.
🧹 Nitpick comments (4)
Deepgram/Clients/Agent/v2/Websocket/Client.cs (4)
51-53
: Unused parameteraddons
Theaddons
parameter here is never used in the method. If this is intentional, consider removing it or adding documentation explaining why it exists.
105-434
: Unify base subscription vs. local event subscription
Not all subscribe methods callbase.Subscribe
; some attach directly to private event fields, while others rely on the base call. This discontinuity complicates event unsubscription and may lead to inconsistent code paths.
577-577
: Dispose parsedJsonDocument
JsonDocument
is disposable. Wrapping it with ausing var data = JsonDocument.Parse(response);
ensures proper disposal for improved memory management.
849-855
: Compile the Regex for better performance
Usingnew Regex(pattern, RegexOptions.Compiled)
can provide performance benefits if the same pattern is used multiple times. Though minor for single usage, it’s a simple improvement.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (50)
Deepgram.Dev.sln
(3 hunks)Deepgram/AgentWebSocketClient.cs
(1 hunks)Deepgram/ClientFactory.cs
(2 hunks)Deepgram/Clients/Agent/v2/Websocket/Client.cs
(1 hunks)Deepgram/Clients/Agent/v2/Websocket/Constants.cs
(1 hunks)Deepgram/Clients/Agent/v2/Websocket/ResponseEvent.cs
(1 hunks)Deepgram/Clients/Agent/v2/Websocket/UriSegments.cs
(1 hunks)Deepgram/Clients/Interfaces/v2/IAgentWebSocketClient.cs
(1 hunks)Deepgram/Deepgram.csproj
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/Agent.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/AgentAudioDoneResponse.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/AgentStartedSpeakingResponse.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/AgentThinkingResponse.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/AgentType.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/Audio.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/AudioResponse.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/CloseResponse.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/Context.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/ControlMessage.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/ConversationTextResponse.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/ErrorResponse.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/Function.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/FunctionCallRequestResponse.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/FunctionCallResponseSchema.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/FunctionCallingResponse.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/Header.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/InjectAgentMessageSchema.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/InjectionRefusedResponse.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/Input.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/InstructionsUpdatedResponse.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/Item.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/KeepAliveSchema.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/Listen.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/OpenResponse.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/Output.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/Parameters.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/Properties.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/Provider.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/SettingsAppliedResponse.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/SettingsConfigurationSchema.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/Speak.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/SpeakUpdatedResponse.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/Think.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/UnhandledResponse.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/UpdateInstructionsSchema.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/UpdateSpeakSchema.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/UserStartedSpeakingResponse.cs
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/WelcomeResponse.cs
(1 hunks)examples/agent/websocket/simple/Agent.csproj
(1 hunks)examples/agent/websocket/simple/Program.cs
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (44)
- Deepgram/Deepgram.csproj
- Deepgram/Models/Agent/v2/WebSocket/UnhandledResponse.cs
- Deepgram/Models/Agent/v2/WebSocket/ErrorResponse.cs
- Deepgram/Models/Agent/v2/WebSocket/OpenResponse.cs
- Deepgram/Models/Agent/v2/WebSocket/CloseResponse.cs
- Deepgram/Models/Agent/v2/WebSocket/SettingsAppliedResponse.cs
- Deepgram/Models/Agent/v2/WebSocket/Speak.cs
- Deepgram/Models/Agent/v2/WebSocket/UserStartedSpeakingResponse.cs
- Deepgram/AgentWebSocketClient.cs
- examples/agent/websocket/simple/Agent.csproj
- Deepgram/Models/Agent/v2/WebSocket/ControlMessage.cs
- Deepgram/Models/Agent/v2/WebSocket/KeepAliveSchema.cs
- Deepgram/Models/Agent/v2/WebSocket/Properties.cs
- Deepgram/Clients/Agent/v2/Websocket/ResponseEvent.cs
- Deepgram/Models/Agent/v2/WebSocket/FunctionCallRequestResponse.cs
- Deepgram/Clients/Agent/v2/Websocket/Constants.cs
- Deepgram/Models/Agent/v2/WebSocket/FunctionCallResponseSchema.cs
- Deepgram/Models/Agent/v2/WebSocket/UpdateInstructionsSchema.cs
- Deepgram/Models/Agent/v2/WebSocket/AgentAudioDoneResponse.cs
- Deepgram/Clients/Agent/v2/Websocket/UriSegments.cs
- Deepgram/Models/Agent/v2/WebSocket/SpeakUpdatedResponse.cs
- Deepgram/Models/Agent/v2/WebSocket/UpdateSpeakSchema.cs
- Deepgram/Models/Agent/v2/WebSocket/Provider.cs
- Deepgram/Models/Agent/v2/WebSocket/AgentStartedSpeakingResponse.cs
- Deepgram/Models/Agent/v2/WebSocket/Listen.cs
- Deepgram/Models/Agent/v2/WebSocket/FunctionCallingResponse.cs
- Deepgram/Models/Agent/v2/WebSocket/InstructionsUpdatedResponse.cs
- Deepgram/Models/Agent/v2/WebSocket/WelcomeResponse.cs
- Deepgram/Models/Agent/v2/WebSocket/Item.cs
- Deepgram/Models/Agent/v2/WebSocket/Audio.cs
- Deepgram/Models/Agent/v2/WebSocket/Output.cs
- Deepgram/Models/Agent/v2/WebSocket/SettingsConfigurationSchema.cs
- Deepgram/Models/Agent/v2/WebSocket/Think.cs
- Deepgram/Models/Agent/v2/WebSocket/AudioResponse.cs
- Deepgram/Models/Agent/v2/WebSocket/InjectionRefusedResponse.cs
- Deepgram/Models/Agent/v2/WebSocket/ConversationTextResponse.cs
- Deepgram/Models/Agent/v2/WebSocket/Context.cs
- Deepgram/Models/Agent/v2/WebSocket/Header.cs
- Deepgram/Models/Agent/v2/WebSocket/AgentThinkingResponse.cs
- Deepgram/Models/Agent/v2/WebSocket/Agent.cs
- Deepgram/Models/Agent/v2/WebSocket/Input.cs
- Deepgram/Models/Agent/v2/WebSocket/Function.cs
- Deepgram.Dev.sln
- Deepgram/Clients/Interfaces/v2/IAgentWebSocketClient.cs
🧰 Additional context used
📓 Learnings (1)
Deepgram/ClientFactory.cs (1)
Learnt from: dvonthenen
PR: deepgram/deepgram-dotnet-sdk#347
File: Deepgram/ClientFactory.cs:146-161
Timestamp: 2024-11-12T11:33:27.266Z
Learning: In `Deepgram/ClientFactory.cs`, the method `CreateListenWebSocketClient(int version, ...)` is intentionally returning `object` as a placeholder because there is only one version of the client. It should not be suggested to change the return type until multiple versions are implemented.
🔇 Additional comments (7)
Deepgram/Clients/Agent/v2/Websocket/Client.cs (1)
51-53
: Consider switching fromCancellationTokenSource
toCancellationToken
This echoes a prior suggestion (lines 51-53) that remains unaddressed. Accepting aCancellationToken
instead of aCancellationTokenSource
heightens flexibility for callers and aligns with .NET best practices.Deepgram/Models/Agent/v2/WebSocket/InjectAgentMessageSchema.cs (1)
23-26
: Verify necessity ofRegex.Unescape
Regex.Unescape
inToString()
might lead to unexpected transformations if the serialized JSON contains escape sequences like “\n”. Confirm this behavior suits your needs.Deepgram/Models/Agent/v2/WebSocket/Parameters.cs (1)
26-29
: Ask for confirmation ofRegex.Unescape
usage
Similar to other classes, the call toRegex.Unescape
can alter valid escape sequences. Consider double-checking its necessity if the output must remain raw JSON.Deepgram/Models/Agent/v2/WebSocket/AgentType.cs (2)
9-28
: LGTM! Well-structured enum definition.The
AgentType
enum is well-organized, extendingWebSocketType
with agent-specific states in a logical flow from connection states to various agent interaction states.
30-40
: LGTM! Clear and consistent constant definitions.The
AgentClientTypes
class provides a clean set of constants for message types with consistent naming conventions.Deepgram/ClientFactory.cs (2)
18-27
: LGTM! Well-documented client creation method.The implementation follows the established pattern for creating latest version clients, with proper XML documentation and type-safe return value.
122-129
: LGTM! Consistent with codebase patterns.The versioned method correctly follows the codebase pattern of returning
object
as a placeholder until multiple versions are implemented.
@naomi-lgbt we'll want to add a link reference to the Readme to highlight the agent examples see this section: https://github.com/deepgram/deepgram-dotnet-sdk/tree/feat/agent?tab=readme-ov-file#example-code |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (1)
Deepgram/Clients/Interfaces/v2/IAgentWebSocketClient.cs (1)
143-143
:⚠️ Potential issueFix inconsistent parameter naming.
The
_cancellationToken
parameter name starts with an underscore, which is inconsistent with C# naming conventions and other parameters in the interface.Also applies to: 165-165, 173-173
🧹 Nitpick comments (3)
Deepgram/Clients/Interfaces/v2/IAgentWebSocketClient.cs (3)
9-12
: Fix interface documentation.The XML comment incorrectly states that the interface "Implements" version 2. Interfaces define or specify contracts rather than implement them.
-/// Implements version 2 of the Agent Client. +/// Defines the contract for version 2 of the Agent Client.
18-19
: Consider reordering parameters for better usability.The
Connect
method's parameter order could be improved by grouping required parameters first, followed by optional parameters.-public Task<bool> Connect(SettingsConfigurationSchema options, CancellationTokenSource? cancelToken = null, Dictionary<string, string>? addons = null, - Dictionary<string, string>? headers = null); +public Task<bool> Connect( + SettingsConfigurationSchema options, + Dictionary<string, string>? headers = null, + Dictionary<string, string>? addons = null, + CancellationTokenSource? cancelToken = null);
12-13
: Add thread safety and exception documentation.Consider adding interface-level documentation about:
- Thread safety guarantees
- Common exceptions that might be thrown
- Any specific implementation requirements
This will help implementers better understand the contract requirements.
/// <summary> /// Defines the contract for version 2 of the Agent Client. +/// </summary> +/// <remarks> +/// Implementations of this interface should be thread-safe. +/// Common exceptions that may be thrown include: +/// <list type="bullet"> +/// <item><description>InvalidOperationException when operations are called in invalid states</description></item> +/// <item><description>WebSocketException for connection-related issues</description></item> +/// </list> /// </summary> public interface IAgentWebSocketClient
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
Deepgram/Clients/Interfaces/v2/IAgentWebSocketClient.cs
(1 hunks)
🔇 Additional comments (2)
Deepgram/Clients/Interfaces/v2/IAgentWebSocketClient.cs (2)
1-8
: LGTM!The file header follows best practices with proper copyright notice, license information, and namespace organization.
176-188
: LGTM!The helper methods are well-documented and provide clear functionality for checking the WebSocket connection state.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
♻️ Duplicate comments (1)
Deepgram/Models/Agent/v2/WebSocket/Context.cs (1)
7-16
: 🛠️ Refactor suggestionConsider using a more specific type than List.
Using
List<object>
loses type safety and makes it harder to work with the messages. Consider creating a specific type for messages or using a more specific base type.Additionally, please add XML documentation comments for the properties to describe their purpose and expected values:
+ /// <summary> + /// Gets or sets the list of messages in the context. + /// </summary> [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("messages")] public List<object>? Messages { get; set; } + /// <summary> + /// Gets or sets a value indicating whether to replay the context. + /// </summary> [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] [JsonPropertyName("replay")] public bool? Replay { get; set; }🧹 Nitpick comments (3)
Deepgram/Models/Agent/v2/WebSocket/Context.cs (1)
18-24
: Improve error handling in ToString method.The current implementation doesn't handle serialization errors. Consider adding try-catch block:
public override string ToString() { - return Regex.Unescape(JsonSerializer.Serialize(this, JsonSerializeOptions.DefaultOptions)); + try + { + return Regex.Unescape(JsonSerializer.Serialize(this, JsonSerializeOptions.DefaultOptions)); + } + catch (JsonException ex) + { + return $"Error serializing {nameof(Context)}: {ex.Message}"; + } }examples/agent/websocket/simple/Program.cs (2)
51-55
: Use Path.Combine for file paths and add file access error handling.File operations should use
Path.Combine
for path construction and include proper error handling.-if (File.Exists($"output_{audioFileCount}.wav")) +var outputPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"output_{audioFileCount}.wav"); +if (File.Exists(outputPath)) { - File.Delete($"output_{audioFileCount}.wav"); + try + { + File.Delete(outputPath); + } + catch (IOException ex) + { + Console.WriteLine($"Error deleting file: {ex.Message}"); + return; + } }Also applies to: 118-122
38-186
: Improve event handler organization and logging.The event handlers could be better organized and include more meaningful logging:
- Group related handlers together (e.g., agent events, audio events)
- Add type-specific information to logs
Example for one group of handlers:
+// Agent state events await agentClient.Subscribe(new EventHandler<AgentStartedSpeakingResponse>((sender, e) => { - Console.WriteLine($"----> {e} received"); + Console.WriteLine($"Agent started speaking: SessionId={e.SessionId}"); })); await agentClient.Subscribe(new EventHandler<AgentThinkingResponse>((sender, e) => { - Console.WriteLine($"----> {e} received"); + Console.WriteLine($"Agent thinking: SessionId={e.SessionId}"); }));📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro📒 Files selected for processing (4)
.gitignore
(1 hunks)Deepgram/Models/Agent/v2/WebSocket/Context.cs
(1 hunks)examples/agent/websocket/simple/Agent.csproj
(1 hunks)examples/agent/websocket/simple/Program.cs
(1 hunks)✅ Files skipped from review due to trivial changes (1)
- .gitignore
🔇 Additional comments (7)
examples/agent/websocket/simple/Agent.csproj (3)
1-8
: LGTM! Good project configuration choices.The project is well-configured with:
- Latest .NET 8.0 LTS version
- Nullable reference types for better type safety
- Implicit usings for cleaner code
15-17
: LGTM! Appropriate namespace configuration.The global using directive for the Deepgram namespace will help reduce code duplication across files.
10-13
: Verify project reference paths.The project references use deep relative paths (
..\..\..\..\
). While functional, this could be fragile if the project structure changes.Run this script to verify the project structure:
✅ Verification successful
Project references are correctly structured
The referenced projects exist at the expected locations and the relative paths are correct for the current project structure. While the paths use multiple parent directory traversals, this is consistent with the repository's organization of example projects.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Verify project references exist and check for alternative path options # Check if referenced projects exist fd -e csproj -x echo "Found project: {}" # Look for .sln files to understand solution structure fd -e sln -x echo "Found solution: {}"Length of output: 2635
Deepgram/Models/Agent/v2/WebSocket/Context.cs (1)
7-25
: Verify the usage of JsonSerializeOptions.DefaultOptions.Let's verify that
JsonSerializeOptions.DefaultOptions
is properly defined and accessible.✅ Verification successful
JsonSerializeOptions.DefaultOptions is properly defined and widely used
The static property is correctly implemented in the internal JsonSerializeOptions class, providing consistent serialization settings across the codebase with web-compatible defaults and indented formatting.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Search for JsonSerializeOptions class definition and its DefaultOptions property ast-grep --pattern 'class JsonSerializeOptions { $$$ static $_DefaultOptions$_ { $$$ } $$$ }'Length of output: 107
Script:
#!/bin/bash # Search for JsonSerializeOptions in all files echo "=== Searching for JsonSerializeOptions ===" rg -l "JsonSerializeOptions" echo -e "\n=== Searching for JsonSerializeOptions with context ===" rg "JsonSerializeOptions" -A 5 -B 5 echo -e "\n=== Searching for DefaultOptions in .cs files ===" rg "DefaultOptions" --type csharpLength of output: 67888
examples/agent/websocket/simple/Program.cs (3)
29-31
: Add API key validation and error handling.The code passes an empty API key to
CreateAgentWebSocketClient
. This will likely cause runtime issues when attempting to connect to the Deepgram API.
191-191
: Invalid OpenAI model name "gpt-4o-mini".The model name appears to be a typo. OpenAI doesn't have a model named "gpt-4o-mini".
198-203
: Enhance connection error handling.The connection failure handling is minimal. Consider adding retry logic and more detailed error information.
// Copyright 2024 Deepgram .NET SDK contributors. All Rights Reserved. | ||
// Use of this source code is governed by a MIT license that can be found in the LICENSE file. | ||
// SPDX-License-Identifier: MIT | ||
|
||
namespace Deepgram.Models.Agent.v2.WebSocket; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add missing using directives.
The following using directives are required:
+using System.Text.RegularExpressions;
+using System.Text.Json;
+using System.Text.Json.Serialization;
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
// Copyright 2024 Deepgram .NET SDK contributors. All Rights Reserved. | |
// Use of this source code is governed by a MIT license that can be found in the LICENSE file. | |
// SPDX-License-Identifier: MIT | |
namespace Deepgram.Models.Agent.v2.WebSocket; | |
// Copyright 2024 Deepgram .NET SDK contributors. All Rights Reserved. | |
// Use of this source code is governed by a MIT license that can be found in the LICENSE file. | |
// SPDX-License-Identifier: MIT | |
using System.Text.RegularExpressions; | |
using System.Text.Json; | |
using System.Text.Json.Serialization; | |
namespace Deepgram.Models.Agent.v2.WebSocket; |
// Microphone streaming | ||
var microphone = new Microphone(agentClient.SendBinary); | ||
microphone.Start(); | ||
|
||
// Wait for the user to press a key | ||
Console.ReadKey(); | ||
|
||
// Stop the microphone | ||
microphone.Stop(); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Improve microphone resource management.
The microphone should be properly disposed of to ensure resources are cleaned up.
-var microphone = new Microphone(agentClient.SendBinary);
-microphone.Start();
+using var microphone = new Microphone(agentClient.SendBinary);
+try
+{
+ microphone.Start();
+ // Wait for the user to press a key
+ Console.ReadKey();
+}
+finally
+{
+ microphone.Stop();
+}
-// Wait for the user to press a key
-Console.ReadKey();
-
-// Stop the microphone
-microphone.Stop();
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
// Microphone streaming | |
var microphone = new Microphone(agentClient.SendBinary); | |
microphone.Start(); | |
// Wait for the user to press a key | |
Console.ReadKey(); | |
// Stop the microphone | |
microphone.Stop(); | |
// Microphone streaming | |
using var microphone = new Microphone(agentClient.SendBinary); | |
try | |
{ | |
microphone.Start(); | |
// Wait for the user to press a key | |
Console.ReadKey(); | |
} | |
finally | |
{ | |
microphone.Stop(); | |
} | |
try | ||
{ | ||
// Initialize Library with default logging | ||
// Normal logging is "Info" level | ||
Deepgram.Library.Initialize(); | ||
// OR very chatty logging | ||
//Deepgram.Library.Initialize(LogLevel.Verbose); // LogLevel.Default, LogLevel.Debug, LogLevel.Verbose | ||
|
||
// Initialize the microphone library | ||
Deepgram.Microphone.Library.Initialize(); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Enhance library initialization with proper cleanup.
The library initialization should be wrapped in a try-finally block to ensure proper cleanup even if an exception occurs during initialization.
try
{
// Initialize Library with default logging
// Normal logging is "Info" level
Deepgram.Library.Initialize();
- // OR very chatty logging
- //Deepgram.Library.Initialize(LogLevel.Verbose); // LogLevel.Default, LogLevel.Debug, LogLevel.Verbose
+ // Initialize the microphone library
+ try
+ {
+ Deepgram.Microphone.Library.Initialize();
+ }
+ catch
+ {
+ Deepgram.Library.Terminate();
+ throw;
+ }
- // Initialize the microphone library
- Deepgram.Microphone.Library.Initialize();
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
try | |
{ | |
// Initialize Library with default logging | |
// Normal logging is "Info" level | |
Deepgram.Library.Initialize(); | |
// OR very chatty logging | |
//Deepgram.Library.Initialize(LogLevel.Verbose); // LogLevel.Default, LogLevel.Debug, LogLevel.Verbose | |
// Initialize the microphone library | |
Deepgram.Microphone.Library.Initialize(); | |
try | |
{ | |
// Initialize Library with default logging | |
// Normal logging is "Info" level | |
Deepgram.Library.Initialize(); | |
// Initialize the microphone library | |
try | |
{ | |
Deepgram.Microphone.Library.Initialize(); | |
} | |
catch | |
{ | |
Deepgram.Library.Terminate(); | |
throw; | |
} |
using (BinaryWriter writer = new BinaryWriter(File.Open($"output_{audioFileCount}.wav", FileMode.Append))) | ||
{ | ||
Console.WriteLine("Adding WAV header to output.wav"); | ||
byte[] wavHeader = new byte[44]; | ||
int sampleRate = 48000; | ||
short bitsPerSample = 16; | ||
short channels = 1; | ||
int byteRate = sampleRate * channels * (bitsPerSample / 8); | ||
short blockAlign = (short)(channels * (bitsPerSample / 8)); | ||
|
||
wavHeader[0] = 0x52; // R | ||
wavHeader[1] = 0x49; // I | ||
wavHeader[2] = 0x46; // F | ||
wavHeader[3] = 0x46; // F | ||
wavHeader[4] = 0x00; // Placeholder for file size (will be updated later) | ||
wavHeader[5] = 0x00; // Placeholder for file size (will be updated later) | ||
wavHeader[6] = 0x00; // Placeholder for file size (will be updated later) | ||
wavHeader[7] = 0x00; // Placeholder for file size (will be updated later) | ||
wavHeader[8] = 0x57; // W | ||
wavHeader[9] = 0x41; // A | ||
wavHeader[10] = 0x56; // V | ||
wavHeader[11] = 0x45; // E | ||
wavHeader[12] = 0x66; // f | ||
wavHeader[13] = 0x6D; // m | ||
wavHeader[14] = 0x74; // t | ||
wavHeader[15] = 0x20; // Space | ||
wavHeader[16] = 0x10; // Subchunk1Size (16 for PCM) | ||
wavHeader[17] = 0x00; // Subchunk1Size | ||
wavHeader[18] = 0x00; // Subchunk1Size | ||
wavHeader[19] = 0x00; // Subchunk1Size | ||
wavHeader[20] = 0x01; // AudioFormat (1 for PCM) | ||
wavHeader[21] = 0x00; // AudioFormat | ||
wavHeader[22] = (byte)channels; // NumChannels | ||
wavHeader[23] = 0x00; // NumChannels | ||
wavHeader[24] = (byte)(sampleRate & 0xFF); // SampleRate | ||
wavHeader[25] = (byte)((sampleRate >> 8) & 0xFF); // SampleRate | ||
wavHeader[26] = (byte)((sampleRate >> 16) & 0xFF); // SampleRate | ||
wavHeader[27] = (byte)((sampleRate >> 24) & 0xFF); // SampleRate | ||
wavHeader[28] = (byte)(byteRate & 0xFF); // ByteRate | ||
wavHeader[29] = (byte)((byteRate >> 8) & 0xFF); // ByteRate | ||
wavHeader[30] = (byte)((byteRate >> 16) & 0xFF); // ByteRate | ||
wavHeader[31] = (byte)((byteRate >> 24) & 0xFF); // ByteRate | ||
wavHeader[32] = (byte)blockAlign; // BlockAlign | ||
wavHeader[33] = 0x00; // BlockAlign | ||
wavHeader[34] = (byte)bitsPerSample; // BitsPerSample | ||
wavHeader[35] = 0x00; // BitsPerSample | ||
wavHeader[36] = 0x64; // d | ||
wavHeader[37] = 0x61; // a | ||
wavHeader[38] = 0x74; // t | ||
wavHeader[39] = 0x61; // a | ||
wavHeader[40] = 0x00; // Placeholder for data chunk size (will be updated later) | ||
wavHeader[41] = 0x00; // Placeholder for data chunk size (will be updated later) | ||
wavHeader[42] = 0x00; // Placeholder for data chunk size (will be updated later) | ||
wavHeader[43] = 0x00; // Placeholder for data chunk size (will be updated later) | ||
|
||
writer.Write(wavHeader); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Extract WAV header creation into a separate method.
The WAV header creation logic is complex and uses magic numbers. Consider extracting it into a separate method with proper constants.
+ private static byte[] CreateWavHeader(int sampleRate, short bitsPerSample, short channels)
+ {
+ const int WAV_HEADER_SIZE = 44;
+ const int PCM_SUBCHUNK_SIZE = 16;
+ const short PCM_AUDIO_FORMAT = 1;
+
+ var wavHeader = new byte[WAV_HEADER_SIZE];
+ int byteRate = sampleRate * channels * (bitsPerSample / 8);
+ short blockAlign = (short)(channels * (bitsPerSample / 8));
+
+ // RIFF header
+ WriteString(wavHeader, 0, "RIFF");
+ // File size placeholder
+ WriteInt32(wavHeader, 4, 0);
+ // WAVE header
+ WriteString(wavHeader, 8, "WAVE");
+ // fmt chunk
+ WriteString(wavHeader, 12, "fmt ");
+ WriteInt32(wavHeader, 16, PCM_SUBCHUNK_SIZE);
+ WriteInt16(wavHeader, 20, PCM_AUDIO_FORMAT);
+ WriteInt16(wavHeader, 22, channels);
+ WriteInt32(wavHeader, 24, sampleRate);
+ WriteInt32(wavHeader, 28, byteRate);
+ WriteInt16(wavHeader, 32, blockAlign);
+ WriteInt16(wavHeader, 34, bitsPerSample);
+ // data chunk
+ WriteString(wavHeader, 36, "data");
+ WriteInt32(wavHeader, 40, 0);
+
+ return wavHeader;
+ }
Committable suggestion skipped: line range outside the PR's diff.
I tested the agent example and it runs with microphone successfully after I had to setup a symlink to port audio lib, so .NET could find it on my Mac: But I think We might need to remove it. 2025-01-29 14:36:02.016 [Error] ProcessTextMessage: System.ArgumentException thrown Requested value 'EndOfThought' was not found.
----> {
"type": "ConversationText",
"role": "assistant",
"content": "Hello!"
} received
----> Audio received
----> {
"type": "AgentStartedSpeaking",
"total_latency": 1.583769296,
"tts_latency": 0.533172957,
"ttt_latency": 0.465769599
} received
----> Audio received
----> Audio received
----> Audio received
----> Audio received
----> Audio received
----> Audio received
----> Audio received
----> Audio received
----> Audio received
----> Audio received
----> Audio received
----> {
"type": "ConversationText",
"role": "assistant",
"content": "How can I assist you today?"
|
Proposed changes
Types of changes
What types of changes does your code introduce to the community .NET SDK?
Put an
x
in the boxes that applyChecklist
Put an
x
in the boxes that apply. You can also fill these out after creating the PR. If you're unsure about any of them, don't hesitate to ask. We're here to help! This is simply a reminder of what we are going to look for before merging your code.Further comments
Summary by CodeRabbit
New Features
New Projects
Enhancements